package com.bruce.ai.alibaba.agentcard.discovery.retry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Predicate;

/**
 * 高级重试策略类
 * 支持多种重试算法和条件判断
 */
public class RetryStrategy {
    
    private static final Logger logger = LoggerFactory.getLogger(RetryStrategy.class);
    
    private final int maxRetries;
    private final long baseDelayMs;
    private final long maxDelayMs;
    private final double jitterFactor;
    private final RetryAlgorithm algorithm;
    private final Predicate<Exception> retryCondition;
    
    public RetryStrategy(Builder builder) {
        this.maxRetries = builder.maxRetries;
        this.baseDelayMs = builder.baseDelayMs;
        this.maxDelayMs = builder.maxDelayMs;
        this.jitterFactor = builder.jitterFactor;
        this.algorithm = builder.algorithm;
        this.retryCondition = builder.retryCondition;
    }
    
    /**
     * 计算重试延迟
     * @param attempt 当前重试次数（从1开始）
     * @return 延迟时间（毫秒）
     */
    public long calculateDelay(int attempt) {
        long delay;
        
        switch (algorithm) {
            case EXPONENTIAL_BACKOFF:
                delay = (long) (baseDelayMs * Math.pow(2, attempt - 1));
                break;
                
            case LINEAR_BACKOFF:
                delay = baseDelayMs * attempt;
                break;
                
            case FIXED_DELAY:
                delay = baseDelayMs;
                break;
                
            case FIBONACCI_BACKOFF:
                delay = baseDelayMs * fibonacci(attempt);
                break;
                
            default:
                delay = baseDelayMs;
        }
        
        // 应用最大延迟限制
        delay = Math.min(delay, maxDelayMs);
        
        // 添加抖动以避免雷群效应
        if (jitterFactor > 0) {
            double jitter = ThreadLocalRandom.current().nextDouble(-jitterFactor, jitterFactor);
            delay = (long) (delay * (1 + jitter));
        }
        
        return Math.max(delay, 0);
    }
    
    /**
     * 判断是否应该重试
     * @param exception 发生的异常
     * @param attempt 当前重试次数
     * @return 是否应该重试
     */
    public boolean shouldRetry(Exception exception, int attempt) {
        if (attempt >= maxRetries) {
            return false;
        }
        
        return retryCondition.test(exception);
    }
    
    /**
     * 计算斐波那契数列
     */
    private long fibonacci(int n) {
        if (n <= 1) return 1;
        if (n == 2) return 1;
        
        long a = 1, b = 1;
        for (int i = 3; i <= n; i++) {
            long temp = a + b;
            a = b;
            b = temp;
        }
        return b;
    }
    
    public int getMaxRetries() {
        return maxRetries;
    }
    
    public long getBaseDelayMs() {
        return baseDelayMs;
    }
    
    public long getMaxDelayMs() {
        return maxDelayMs;
    }
    
    public RetryAlgorithm getAlgorithm() {
        return algorithm;
    }
    
    /**
     * 重试算法枚举
     */
    public enum RetryAlgorithm {
        EXPONENTIAL_BACKOFF,  // 指数退避
        LINEAR_BACKOFF,       // 线性退避
        FIXED_DELAY,          // 固定延迟
        FIBONACCI_BACKOFF     // 斐波那契退避
    }
    
    /**
     * 构建器类
     */
    public static class Builder {
        private int maxRetries = 3;
        private long baseDelayMs = 1000;
        private long maxDelayMs = 10000;
        private double jitterFactor = 0.1; // 10% 抖动
        private RetryAlgorithm algorithm = RetryAlgorithm.EXPONENTIAL_BACKOFF;
        private Predicate<Exception> retryCondition = defaultRetryCondition();
        
        public Builder maxRetries(int maxRetries) {
            this.maxRetries = maxRetries;
            return this;
        }
        
        public Builder baseDelay(long baseDelayMs) {
            this.baseDelayMs = baseDelayMs;
            return this;
        }
        
        public Builder maxDelay(long maxDelayMs) {
            this.maxDelayMs = maxDelayMs;
            return this;
        }
        
        public Builder jitterFactor(double jitterFactor) {
            this.jitterFactor = Math.max(0, Math.min(1, jitterFactor));
            return this;
        }
        
        public Builder algorithm(RetryAlgorithm algorithm) {
            this.algorithm = algorithm;
            return this;
        }
        
        public Builder retryCondition(Predicate<Exception> condition) {
            this.retryCondition = condition;
            return this;
        }
        
        public Builder retryOnExceptions(Class<? extends Exception>... exceptionTypes) {
            Set<Class<? extends Exception>> retryableExceptions = new HashSet<>(Arrays.asList(exceptionTypes));
            this.retryCondition = exception -> retryableExceptions.contains(exception.getClass());
            return this;
        }
        
        public RetryStrategy build() {
            return new RetryStrategy(this);
        }
        
        /**
         * 默认重试条件：网络相关异常
         */
        private static Predicate<Exception> defaultRetryCondition() {
            return exception -> {
                // 网络超时异常
                if (exception instanceof SocketTimeoutException) {
                    return true;
                }
                
                // IO异常（但排除某些不可重试的情况）
                if (exception instanceof IOException) {
                    String message = exception.getMessage();
                    if (message != null) {
                        message = message.toLowerCase();
                        // 不重试的情况
                        if (message.contains("401") || message.contains("403") || 
                            message.contains("404") || message.contains("400")) {
                            return false;
                        }
                    }
                    return true;
                }
                
                // 运行时异常中的某些情况
                if (exception instanceof RuntimeException) {
                    String message = exception.getMessage();
                    if (message != null && message.toLowerCase().contains("timeout")) {
                        return true;
                    }
                }
                
                return false;
            };
        }
    }
    
    /**
     * 创建默认重试策略
     */
    public static RetryStrategy defaultStrategy() {
        return new Builder().build();
    }
    
    /**
     * 创建快速重试策略（适用于轻量级操作）
     */
    public static RetryStrategy fastRetry() {
        return new Builder()
                .maxRetries(5)
                .baseDelay(100)
                .maxDelay(2000)
                .algorithm(RetryAlgorithm.EXPONENTIAL_BACKOFF)
                .build();
    }
    
    /**
     * 创建慢重试策略（适用于重量级操作）
     */
    public static RetryStrategy slowRetry() {
        return new Builder()
                .maxRetries(3)
                .baseDelay(2000)
                .maxDelay(30000)
                .algorithm(RetryAlgorithm.EXPONENTIAL_BACKOFF)
                .build();
    }
}